package com.atguigu.gmall.cart.service.impl;

import com.atguigu.gmall.cart.service.CartService;
import com.atguigu.gmall.common.constant.RedisConst;
import com.atguigu.gmall.model.cart.CartInfo;
import com.atguigu.gmall.model.product.SkuInfo;
import com.atguigu.gmall.product.client.ProductFeignClient;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.BoundHashOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

@Service
public class CartServiceImpl implements CartService {

    @Autowired
    private RedisTemplate redisTemplate;

    @Autowired
    private ProductFeignClient productFeignClient;

    /**
     * 添加到购物车
     * @param skuId
     * @param userId
     * @param skuNum
     */
    @Override
    public void addToCart(Long skuId, String userId, Integer skuNum) {
        // 这里分为两种情况，一种是已经登录的用户，一种是未登录的用户，会生成用户零食id
        /**
         * 先查询redis中是否有我们要插入的数据，如果没有的话则直接添加，如果已经存在了，则对属灵进行增加
         */
        // 生成redis中的key，大key
        String cartKey = this.getCartKey(userId);

        // 查询redis中是否有这条数据
        CartInfo cartInfo = (CartInfo) this.redisTemplate.opsForHash().get(cartKey, skuId.toString());
        // 判断cartinfo是否有数据
        if (cartInfo != null){
            // 不等于null 则表示有数据，则只对商品的num进行修改
            cartInfo.setUpdateTime(new Date());
            cartInfo.setSkuNum(cartInfo.getSkuNum()+skuNum);
            // 将实时的价格赋值到对象中
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            // 判断，如果是未选中的状态，将状态改为选中
            if (cartInfo.getIsChecked() == 0){
                cartInfo.setIsChecked(1);
            }

        }else{
            // 如果进入了else 则表示没有查询到数据
            // 使用远程调用将skuinfo查询到
            SkuInfo skuInfo = productFeignClient.getAttrValueList(skuId);
            // 封装存储的数据，将数据存储到redis中
            cartInfo = new CartInfo();

            // 封装数据
            //  创建一个cartInfo
            cartInfo = new CartInfo();
            cartInfo.setSkuId(skuId);
            cartInfo.setCartPrice(productFeignClient.getSkuPrice(skuId));
            cartInfo.setSkuPrice(productFeignClient.getSkuPrice(skuId));
            cartInfo.setSkuNum(skuNum);
            cartInfo.setUserId(userId);
            cartInfo.setImgUrl(skuInfo.getSkuDefaultImg());
            cartInfo.setSkuName(skuInfo.getSkuName());
            cartInfo.setCreateTime(new Date());
            cartInfo.setUpdateTime(new Date());

        }
        // 最后将数据更新到redis中
        this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfo);
    }

    /**
     * 查询数据库列表
     * @param userId
     * @param userTempId
     * @return
     */
    @Override
    public List<CartInfo> getCartList(String userId, String userTempId) {

        // 分为两种情况
        /*
        一种是用户已经登录的情况
        一种是用户未登录的情况
         */
        // 判断用户未登录情况
        List<CartInfo> CartInfoList = new ArrayList<>();
        if (StringUtils.isEmpty(userId) && !StringUtils.isEmpty(userTempId)){
            // 如果用户id为空，但是零时用户id不为空，则表示用户没有登录
            // 获取大key
            String cartKey = this.getCartKey(userTempId);
            // 到redis中查询数据
            BoundHashOperations boundHashOperations = this.redisTemplate.boundHashOps(cartKey);
            CartInfoList = boundHashOperations.values();

            // 对list 根据更新的时间进行排序
            CartInfoList.sort((o1,o2)->{
                return o2.getUpdateTime().compareTo(o1.getUpdateTime());
            });

            return CartInfoList;
        }

        // 判断如果用户登录了
        if (!StringUtils.isEmpty(userId)){
            // 如果userid不为空，并且零时id也不为空，则表示需要合并数据了
            // 获取零时id的数据
            String oldCartKey = this.getCartKey(userTempId);
            // redis 获取数据
            BoundHashOperations boundHashOperationsOld = this.redisTemplate.boundHashOps(oldCartKey);

            List<CartInfo> oldList = new ArrayList<>();
            // 获取到新的数据
            String cartKey = this.getCartKey(userId);
            // redis查询数据
            BoundHashOperations boundHashOperations = this.redisTemplate.boundHashOps(cartKey);
            // 创建新的数据list
            List<CartInfo> newList = new ArrayList<>();
            // 表示登录了
            // 再次进行判断
            if (!StringUtils.isEmpty(userId) && !StringUtils.isEmpty(userTempId)){

                if (boundHashOperationsOld != null){
                    oldList = boundHashOperationsOld.values();
                }

                // 判空
                if (boundHashOperations != null){
                    // 如果有数据，在这个if括号中进行操作
                    // 将旧的数据进行循环，判断是否在新的数组中存在，存在则数量进行增加，不存在则直接加到后面
                    oldList.forEach(cartInfoOld -> {
                        if (boundHashOperations.hasKey(cartInfoOld.getSkuId().toString())){
                            // 则获取到数据，将数据的num增加
                            CartInfo cartInfo = (CartInfo) boundHashOperations.get(cartInfoOld.getSkuId().toString());
                            // 将数据里面的num进行修改
                            cartInfo.setSkuNum(cartInfo.getSkuNum() + cartInfoOld.getSkuNum());
                            //设置时间
                            cartInfo.setCreateTime(new Date());
                            cartInfo.setUpdateTime(new Date());

                            // 判断零时数据是否选中，如果选中则设置为1
                            if (cartInfoOld.getIsChecked() == 1){
                                cartInfo.setIsChecked(1);
                            }
                            // 最后将数据放入到缓存中
                            boundHashOperations.put(cartInfo.getSkuId().toString(),cartInfo);
                        }else{
                            // 表示没有出现过
                            cartInfoOld.setCreateTime(new Date());
                            boundHashOperations.put(cartInfoOld.getSkuId().toString(),cartInfoOld);
                        }
                    });
                }

            }else{
                //  不需要合并，直接查询返回数据
                // 获取存储数据的key
                String cartKey1 = this.getCartKey(userId);
                // 查询数据
                CartInfoList = this.redisTemplate.boundHashOps(cartKey1).values();
                // 对数据进行排序
                CartInfoList.sort((o1,o2)->{
                    return o2.getUpdateTime().compareTo(o1.getUpdateTime());
                });

                return CartInfoList;
            }

            // 将零时数据删除
            this.redisTemplate.delete(oldCartKey);

            newList = boundHashOperations.values();
            // 排序
            newList.sort((o1,o2)->{
                return o1.getUpdateTime().compareTo(o2.getUpdateTime());
            });
            return newList;
        }

        return new ArrayList<>();
    }

    /**
     * 设置选中状态
     * @param skuId
     * @param userId
     * @param isChecked
     */
    @Override
    public void checkCart(Long skuId, String userId, Integer isChecked) {
        // 生成redis key
        String cartKey = this.getCartKey(userId);
        // 使用redis 查询数据
        CartInfo cartInfo = (CartInfo) this.redisTemplate.opsForHash().get(cartKey, skuId.toString());
        //  设置状态
        cartInfo.setIsChecked(isChecked);
        // 在放入到缓存中
        this.redisTemplate.opsForHash().put(cartKey,skuId.toString(),cartInfo);
    }

    /**
     * 删除购物车数据
     * @param skuId
     * @param userId
     */
    @Override
    public void deleteCart(Long skuId, String userId) {

        // 生成redis key
        String cartKey = this.getCartKey(userId);
        // 调用redis模板删除数据
        this.redisTemplate.opsForHash().delete(cartKey,skuId.toString());
    }

    /**
     * 根据用户id查询购物车对应选中的商品信息
     * @param userId
     * @return
     */
    @Override
    public List<CartInfo> getCartCheckedList(String userId) {
        String cartKey = this.getCartKey(userId);

        List<CartInfo> cartInfoList = this.redisTemplate.opsForHash().values(cartKey);
        // 对查询到的List集合进行过滤，获取已选中的商品
        List<CartInfo> cartInfoList1 = cartInfoList.stream().filter(cartInfo -> {
            return cartInfo.getIsChecked() == 1;
        }).collect(Collectors.toList());
        return cartInfoList1;
    }

    private String getCartKey(String userId) {
        return RedisConst.USER_KEY_PREFIX + userId + RedisConst.USER_CART_KEY_SUFFIX;
    }
}
